#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <pthread.h>
#include "tcp.h"
#include "pack.h"
#include "file.h"
#include "users.h"


Clnode *client_head = NULL;
//建立tcpsocket
int init(int port)
{
	int sockfd;
	struct sockaddr_in addr;

	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = htonl(INADDR_ANY);

	int opt = SO_REUSEADDR;
	setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
	if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
	{
		close(sockfd);
		perror("bind error:");
		return -1;
	}
	listen(sockfd, 10);					//监听
	init_seq();							//初始化包编号
	return sockfd;
}
//建立epoll服务器
int server()
{
	int sockfd, efd, csockfd;
	int client_num, res, nready, i;
	unsigned int clilen;
	struct epoll_event tep, ep[OPEN_MAX];
	struct sockaddr_in cliaddr;
	char cli_ip[20];

	sockfd = init(34000);				//初始化套接字
	efd = epoll_create(OPEN_MAX);		//创建epoll句柄，监听数目OPEN_MAX
	if (efd == -1)
	{
		perror("epoll_create");
		return 0;
	}

	tep.events = EPOLLIN;				//设置监听套接字事件类型
	tep.data.fd = sockfd;				//设置监听事件的文件描述符为监听套接字
	res = epoll_ctl(efd, EPOLL_CTL_ADD, sockfd, &tep);	//事件注册
	client_num = 0;						//连接数量
	if (res == -1)
	{
		perror("epoll_ctl");			//事件注册提示
		return 0;
	}
	init_packinfo();					//初始化解包结构体
	init_Files();
	while(1)							//服务器监听主循环
	{
		nready = epoll_wait(efd, ep, OPEN_MAX, -1);		//等待事件
		if(nready == -1)						//等待失败提示
		{
			perror("nready");
			return 0;
		}

		for(i = 0 ; i < nready ; i++)			//循环处理活动事件
		{
			if(!(ep[i].events & EPOLLIN))		//判断事件类型
				continue;
			if(client_num >= 10000)				//最大客户端连接数判断
			{
				printf("too many client\n");
				continue;
			}
			if(ep[i].data.fd == sockfd) 			//判断活动事件为监听套接字
			{
				clilen = sizeof(cliaddr);
				csockfd = accept(sockfd, (struct sockaddr *)&cliaddr, &clilen);	//升级为服务套接字
				printf("connected:%s[%d]\n", 
				inet_ntop(AF_INET, &cliaddr.sin_addr, cli_ip, sizeof(cli_ip)), 
				ntohs(cliaddr.sin_port));

				tep.events = EPOLLIN;
				tep.data.fd = csockfd;				//注册事件
				res = epoll_ctl(efd, EPOLL_CTL_ADD, csockfd, &tep);
				if (res == -1)
				{
					perror("epoll_ctl");
					return 0;
				}
				add_client(csockfd, cliaddr);		//增加客户端列表
				list_client();						//显示客户端列表
				client_num++;
			}
			else									//判断为服务套接字
			{	
				csockfd = ep[i].data.fd;
				
				if(recvice(csockfd))			//读取服务套接字中的数据
				{								//并判断是否断开连接，断开连接删除注册事件
					res = epoll_ctl(efd, EPOLL_CTL_DEL, csockfd, NULL);
					if (res == -1)
					{
						perror("epoll_ctl");
						return 0;
					}
					close(csockfd);				//关闭此服务套接字
					client_num--;
				}
				
			}
		}
		
	}

	return 0;
}

//读取socket数据
int recvice(int csockfd)
{
	int len, index;
	pthread_t tid;
	Arg arg;
	char buf[1024], sendbuf[1024];
	memset(buf, 0 ,sizeof(buf));
	len = read(csockfd, buf, sizeof(buf));			
//	printf("recv====");
	//display_buf(buf);			
	clean_packinfo();
	unpack_head(buf);							//解包
	switch(atoi(pack_info.cmd_num))
	{
		case 29:unpack_029(pack_info.addition);
				break;
		case 27:unpack_027(sendbuf, pack_info.addition, csockfd);
				break;
		case 17:index = unpack_017(pack_info.addition, csockfd);		//登陆操作
				pack_018(sendbuf, index);
				sock_send(sendbuf, csockfd);
				send_userlist(index, csockfd);		//发送用户列表
				pack_024(sendbuf, csockfd);
				broad_send(sendbuf, csockfd, "024");	//广播
				break;
		case 22:
				pack_023(sendbuf, unpack_022(pack_info.addition, csockfd));	//注册操作
				sock_send(sendbuf, csockfd);
				break;
		case 16:unpack_016(pack_info.addition, csockfd);
				break;
		case 15:unpack_015(pack_info.addition, len, csockfd);
				break;
		case 13:index = unpack_013(pack_info.addition, csockfd);		//请求上传文件
				if(index < 10)
					creat_file(index);						//创建接收文件
				pack_014(sendbuf, index);					//确认上传
				sock_send(sendbuf, csockfd);
				break;
		case 9:	index = unpack_009(pack_info.addition, csockfd);		//请求下载文件
				if(index < 10)
				{
					arg.pktId = sFiles[index].pktId;
					arg.sockfd = csockfd;
					pthread_create(&tid, NULL, send_file, &arg);	//建立发送文件线程
				}
				else
				{
					pack_010(sendbuf, index);							//发送队列忙碌
					sock_send(sendbuf, csockfd);
				}
				break;
		case 7:	pack_008(sendbuf);										//发送文件列表
				sock_send(sendbuf, csockfd);
				break;
		case 6: printf("disconnect[%d]\n", csockfd);					//离线
				pack_021(sendbuf, csockfd);
				broad_send(sendbuf, csockfd, "021");					//离线广播
				del_client(csockfd);									//删除列表
				list_client();
				return 1;
				break;
		case 5: pack_025_data(sendbuf, pack_info.addition, csockfd);	//聊天数据
				broad_send(sendbuf, csockfd, "025");					//广播转发
				break;
		default: break;
	}
	return 0;
}
//socket发送
void sock_send(char *sendbuf, int sockfd)
{
	write(sockfd, sendbuf, 1024);
//	printf("send====");
//	display_buf(sendbuf);
}
//广播
void broad_send(char *data, int csockfd, char *cmd)
{
	Clnode *p, *act;
	char sendbuf[1024];

	memset(sendbuf, 0, sizeof(sendbuf));
	for(act = client_head; act -> sockfd != csockfd ; act = act -> next);
	for(p = client_head; p != NULL ; p = p -> next)
	{
		if(strlen(p->user_data.Account))
		{
			seq++;
			sprintf(sendbuf, "%ld:%s:%s", seq, cmd, data);
			display_buf(sendbuf);
			write(p -> sockfd, sendbuf, sizeof(sendbuf));
		}
	}
}

//增加客户端列表
void add_client(int csockfd, struct sockaddr_in cliaddr)
{
	Clnode *p, *node, *q;
	char name[20], cli_ip[20];
	int i;

	inet_ntop(AF_INET, &cliaddr.sin_addr, cli_ip, sizeof(cli_ip));
	if(client_head == NULL)
	{
		client_head = (Clnode *)malloc(sizeof(Clnode));
		sprintf(name, "Client%d", 1);            //
		strcpy(client_head -> name , name);
		strcpy(client_head -> ip, cli_ip);
		client_head -> sockfd = csockfd;
		init_user_node(client_head);
		client_head -> next = NULL;
	}
	else if(client_head -> next == NULL)
	{
		node = (Clnode *)malloc(sizeof(Clnode));
		sprintf(name, "Client%d", 2);			//
		strcpy(node -> name ,name);
		strcpy(node -> ip, cli_ip);
		node -> sockfd = csockfd;
		client_head -> next = node;
		init_user_node(node);
		node -> next = NULL;
	}
	else
	{
		p = client_head -> next;
		q = client_head;
		i = 2;
		while(p != NULL)
		{
			p = p -> next;
			q = q -> next;
			i++;
		}

		p = (Clnode *)malloc(sizeof(Clnode));
		sprintf(name, "Client%d", i);
		strcpy(p -> name , name);
		strcpy(p -> ip, cli_ip);
		p -> sockfd = csockfd;
		q -> next = p;
		init_user_node(p);
		p -> next = NULL;
	}
}
//删除客户端列表
void del_client(int csockfd)
{
	Clnode *p, *q;
	
	if(client_head -> sockfd == csockfd)
	{
		p = client_head -> next;
		free(client_head);
		client_head = p;
	}
	else
	{
		p = client_head -> next;
		q = client_head;
		while(p -> next != NULL)
		{
			if(p -> sockfd == csockfd)
				break;
			p = p -> next;
			q = q -> next;
		}
		if(p -> next == NULL)
		{
			q -> next = NULL;
			free(p);
		}
		else
		{
			q -> next = p -> next;
			free(p);
		}
	}	
}
//显示客户端列表
void list_client()
{
	Clnode *p;
	p = client_head;
	printf("=================================\n");
	while(p != NULL)
	{
		printf("[%d]name:%s\tip:%s\n", p -> sockfd
			, p -> name, p -> ip);
		p = p -> next;
	}
	printf("=================================\n");
}
//寻找客户端
Clnode *find_client(int sockfd)
{
	Clnode *p;
	for(p = client_head; p != NULL && p -> sockfd != sockfd ; p = p -> next);
	return p;
}
//初始化用户信息
void init_user_node(Clnode *p)
{
	memset(p->user_data.Account, 0, sizeof(p->user_data.Account));
	memset(p->user_data.Nickname, 0, sizeof(p->user_data.Nickname));
	memset(p->user_data.Motto, 0, sizeof(p->user_data.Motto));
	memset(p->user_data.Email, 0, sizeof(p->user_data.Email));
	p->user_data.Pic = 1;

}
//显示buf
void display_buf(char *buf)
{
	for(int i = 0; i < 1024 ; i++)
	{
		printf("%c", *(buf+i));
	}
	printf("\n");
}